(* The REAL & LONGREAL functions (WriteReal etc) requice 'C' floating point *)
(* so will not work with the unregisterd version of DICE                    *)
(* If you have the registered version of DICE then you must                 *)
(* link with the math library, either:			                    *)
(* m2l x -lm or m2b x -lm , alternatively set -lm in the DCCOPTS env var    *)
(* This is only required if you use the floating point functions:           *)
(* If you only use WriteChar etc, you dont need to link the math library    *)

DEFINITION MODULE FIO ;
(*
 *	Simple but flexible File based I/O system
 *
 *	This module provides a collection of procedures to perform
 *	I/O operations on text files. File access can be sequential
 *      or random.
 *      The following table states the operations that may be applied
 *      according to the file's access mode.
 *
 *                          OPERATIONS
 *
 *              	Rewind	Set &	EOF &	Reads	Writes
 *			------	FindPos	EOLN	-----	------
 *				-------	----
 *      MODE:
 *	Read		y		y	y
 *	Write						y
 *	Random		y	y	y	y	y
 *)


FROM SYSTEM IMPORT ADDRESS ;

CONST
  TabCh     = "\t" ;	(* some useful character constants  *)
  NewLineCh = "\n" ;	(* shouldn't really be here at all! *)
  SpaceCh   = " "  ;

  MaxFiles     = 20 ;	(* open simulataneously *)
  MaxFileName = 500 ;	(* length of filename   *)

TYPE
  File     = LONGINT ;		(* a file descriptor: treat this as OPAQUE *)

  FileName = ARRAY [0..MaxFileName] OF CHAR ;

  Status   = ( UnInitialized, NoError, CantOpenFile, CantCreateFile,
	       TooManyOpen, OpFailed, Overflow ) ;

  EndType  = ( FromStart, FromCurrent, AddToEnd ) ;

  BufferingMode = ( NoBuffer, LineBuffer, FullBuffer ) ;

VAR
  StdIn, StdOut, StdErr : File ;

(* ------------------------- Error Procedures ------------------------- *)

PROCEDURE IOStatus( id : File ) : Status ;

(*
 * Task:	find out the status of the last IO operation
 *		on the given file..
 * Returns:	the status
 *)


PROCEDURE ReportError( id : File ) ;

(*
 * Task:	If the last IO operation on the given file failed,
 *		generate a suitable error message and HALT
 * Returns:	Only if the last IO operation was a success.
 *)


(* -------------------------- Open Procedures ------------------------- *)


PROCEDURE OpenToRead( extName : ARRAY OF CHAR ) : File ;

(*
 * Task:	open a file for reading
 * Returns:	the file descriptor for further use.
 * Status:	NoError if success.
 *		CantOpenFile if failure.
 *)


PROCEDURE OpenToWrite( extName : ARRAY OF CHAR ) : File ;

(*
 * Task:	open a file for writing
 * Returns:	the file descriptor for further use.
 * Status:	NoError if success.
 *		CantCreateFile if failure.
 *)


PROCEDURE OpenForRandom( extName : ARRAY OF CHAR ; Create : BOOLEAN ) : File ;

(*
 * Task:	open a file for random access, creating it [erasing any
 *		previous contents] if Create is set, otherwise leaving
 *		the previous data available for reading.
 * Returns:	the file descriptor for further use.
 * Status:	NoError if success
 *		else:	CantCreateFile if Create
 *			CantOpenFile otherwise
 *)

PROCEDURE SetBuffer( file : File ;
		     mode : BufferingMode ;
		     size : LONGINT ;
		     buff : ADDRESS ) ;
(*
 * Task:	Controls file buffering.
 *	        mode:
 *	        FullBuffer: output flushed only if buffer full
 *	        LineBuffer: output flushed every newline
 *	        NoBuffer  : no buffering at all
 *		Default mode is line buffering.
 *	        For mode = NoBuffer the buf and size arguments should be passed
 *	        as NIL & 0.
 *		For other modes, if buff is not NIL then the first size bytes
 *		of buff are used as the file buffer otherwise the buffer will be
 *		allocated for you.
 *		If buffering is turned on/off for a file representing a
 *		console device, the console device is set to buffered/unbuffered
 *		as well. ie raw/cooked.
 *
 * Access-Mode:	Read,Write or Random
 * Status:	NoError if success
 *		OpFailed otherwise.
 *)

(* ------------------------- Other Procedures ------------------------- *)

(*
 * Notes about the remaining functions:
 *	1).	They will call ReportError [and thus HALT] when given a file
 *		that has not been sussessfully opened in the correct mode.
 *
 *	2).	However, if they themselves fail, they will set
 *		the error status and return painlessly..
 *)


PROCEDURE Close( id : File ) ;

(* Task:	to close the given file (if the file has been opened
 *		successfully, this cannot fail).
 * Access-Mode:	Read, Write or Random
 * Status:	Unitialized
 *)


PROCEDURE FlushFile( f : File ) ;

(* Task:	to flush the given file - force any pending output
 *		to leave the buffer and appear on the screen/physical
 *		file (if the file has been opened successfully, this
 *		cannot fail).
 * Access-Mode:	Read, Write or Random
 * Status:	unchanged
 *)


PROCEDURE EOF( id : File ) : BOOLEAN ;

(*
 * Task:	Finds out whether the end-of-file has been reached
 *		on the given file
 * Returns:	TRUE if so.
 * Access-Mode:	Read or Random
 * Status:	NoError
 *)


PROCEDURE EOLN( id : File ) : BOOLEAN ;

(*
 * Task:	Finds out whether an end-of-line has been reached on the
 *		current file
 * Returns:	True if so.
 * Access-Mode:	Read or Random
 * Status:	NoError
 *)

(* --------------------- Read <object> Procedures --------------------- *)

(*
 * Task:		read an object [of some type]
 * Returns:		the next object of the appropriate type.
 * Access-Mode:		Read or Random
 * NOTE:		ReadString discards leading whitespace,
 *			then reads characters up to the next whitespace
 *			(which is pushed back and left).
 *			ReadLn discards NOTHING: reads the whole rest of line,
 *			discarding the newline itself.
 * Status:		NoError if success,
 *			OpFailed otherwise.
 * NOTE:		Any of these will abort if they encounter premature
 *			EOF.
 *)


PROCEDURE ReadInteger( id : File ) : LONGINT ;
PROCEDURE ReadReal( id : File ) : REAL ;
PROCEDURE ReadLongReal( id : File ) : LONGREAL ;
PROCEDURE ReadChar( id : File ) : CHAR ;
PROCEDURE ReadString( id : File ; VAR object : ARRAY OF CHAR ) ;
PROCEDURE ReadLn( f : File ; VAR s : ARRAY OF CHAR ) ;
PROCEDURE ReadLine( id : File ) ;


(* -------------------- Write <object> Procedures --------------------- *)

(*
 * Task:		Write an object [of some type] to the given file
 * NOTE:		WriteLn simply writes the given message and then
 *			a newline
 * Access-Mode:		Write or Random
 * Status:		NoError if success,
 *			OpFailed otherwise.
 *)


PROCEDURE WriteInteger( id : File ; object : LONGINT ) ;
PROCEDURE WriteReal( id : File ; object : REAL ) ;
PROCEDURE WriteLongReal( id : File ; object : LONGREAL ) ;
PROCEDURE WriteChar( id : File ; object : CHAR ) ;
PROCEDURE WriteString( id : File ; object : ARRAY OF CHAR ) ;
PROCEDURE WriteLn( f : File ; s : ARRAY OF CHAR ) ;
PROCEDURE WriteLine( id : File ) ;


(* -------------------- Random Access Procedures ---------------------- *)


PROCEDURE SetPosition( id : File ; pos : LONGINT ; end : EndType ) ;

(*
 * Task:	position the file pointer on a random access file.
 * Receives:	the file, id, the position, Pos [measured in bytes],
 *		and an indicator of from which end the position is
 *		measured.
 * Access-Mode:	Random
 * Status:	NoError if success,
 *		OpFailed otherwise.
 *)


PROCEDURE FindPosition( id : File ) : LONGINT ;

(*
 * Task:	shows the user the current position in a random access file.
 * Receives:	the file, id.
 * Returns:	the current position
 * Access-Mode:	Random
 * Status:	NoError.
 *)


PROCEDURE Rewind( id : File ) ;

(*
 * Task:	rewind the given file.
 * Access-Mode:	Read or Random
 * Status:	NoError if success,
 *		OpFailed otherwise.
 *)


(* ---------------------- Miscellaneous procedures -------------------- *)


PROCEDURE SkipBlanks( f : File ) ;

(*
 * Task:	skip all leading blanks (spaces or tabs - not newlines)
 *		from the given file.
 *)


PROCEDURE SkipWS( f : File ) ;

(*
 * Task:	Skip all whitespace (spaces, tabs and newlines)..
 *)


PROCEDURE EOFAfterWS( f : File ) : BOOLEAN ;

(*
 * Task:	Skip whitespace and then; is the file at EOF?
 *)


PROCEDURE UnReadChar( id : File ; c : CHAR ) ;

(*
 * Task:	push the given character back onto the given input file
 * Receives:	the file id and the character to push back..
 * Access-Mode:	Read or Random
 * Status:	NoError.
 *)


PROCEDURE ReadNBytes( file : File ; n : LONGINT ; buffer : ADDRESS ) ;

(*
 * Task:	read N bytes from the given file, into the area of memory
 *		starting at Buffer.
 * Suggestion:	use SIZE(var) and ADR(var) when calling
 * Access-Mode:	Read or Random
 * Status:	NoError if success,
 *		OpFailed otherwise.
 * NOTE:	This will abort if it encounters a premature EOF.
 *)


PROCEDURE WriteNBytes( file : File ; n : LONGINT ; buffer : ADDRESS ) ;

(*
 * Task:	Write N bytes to the given file, into the area of memory
 *		starting at Buffer.
 * Suggestion:	use SIZE(var) and ADR(var) when calling
 * Access-Mode:	Write or Random
 * Status:	NoError if success,
 *		OpFailed otherwise.
 *)


PROCEDURE WriteRealFmt( file : File ; r : REAL ; width, decplaces : LONGINT ) ;

(* Task:	writes the given real to the given file, formatting the value
 *		so that it is right justified in a field of the given width,
 *		and contains the given number of decimal places.
 * Access-Mode:	Write or Random
 * Status:	NoError if success,
 *		OpFailed otherwise.
 *)


PROCEDURE WriteLongRealFmt( file : File ; r : LONGREAL ;
			    width, decplaces : LONGINT ) ;

(* Task:	writes the given longreal to the given file, formatting the
 *		value so that it is right justified in a field of the given
 *		width, and contains the given number of decimal places.
 * Access-Mode:	Write or Random
 * Status:	NoError if success,
 *		OpFailed otherwise.
 *)

(*------- Some useful functions that shouldn't really be here either ---------*)

PROCEDURE Delete( name : ARRAY OF CHAR ) : BOOLEAN ;
(* Status: Returns TRUE on success, FALSE otherwise *)

PROCEDURE Rename( from, to : ARRAY OF CHAR ) : BOOLEAN ;
(* Status: Returns TRUE on success, FALSE otherwise *)

END FIO.
